//---------------------------------------------------------------------------

#include <vcl.h>
#include <GLS.Keyboard.hpp>
#include <stdlib.h>

#pragma hdrstop

#include "fTerrainC.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "GLS.LensFlare"
#pragma link "GLS.VectorGeometry"
#pragma link "Sounds.BASS"
#pragma link "GLS.SoundManager"
#pragma link "GLS.SceneViewer"
#pragma link "GLS.SkyDome"
#pragma link "GLS.BitmapFont"
#pragma link "GLS.HUDObjects"
#pragma link "GLS.Texture"
#pragma link "GLS.Cadencer"
#pragma link "GLS.HeightData"
#pragma link "GLS.Objects"
#pragma link "GLS.TerrainRenderer"
#pragma link "GLS.Scene"
#pragma link "GLS.Keyboard"
#pragma link "GLS.BaseClasses"
#pragma link "GLS.Coordinates"

#pragma link "GLS.Material"
#pragma link "GLS.FileMP3"
#pragma link "GLS.SoundManager"
#pragma resource "*.dfm"
TForm1* Form1;

float random(void)
{
    return (float)(rand() & 0x1FFF) / (float)0x1FFF;
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    TFileName Path = GetCurrentAssetPath();
    SetCurrentDir(Path + "\\texture");

    // 8 MB height data cache
    // Note this is the data size in terms of elevation samples, it does not
    // take into account all the data required/allocated by the renderer
    GLBitmapHDS1->MaxPoolSize = 8 * 1024 * 1024;
    // specify height map data
    GLBitmapHDS1->Picture->LoadFromFile("terrain.bmp");
    // load the texture maps
    GLMaterialLibrary1->Materials->Items[0]
        ->Material->Texture->Image->LoadFromFile("snow512.jpg");
    GLMaterialLibrary1->Materials->Items[1]
        ->Material->Texture->Image->LoadFromFile("detailmap.jpg");
    SPMoon->Material->Texture->Image->LoadFromFile("moon.bmp");
    SPSun->Material->Texture->Image->LoadFromFile("flare1.bmp");
    // apply texture map scale (our heightmap size is 256)
    TerrainRenderer1->TilesPerTexture = 256.0 / TerrainRenderer1->TileSize;
    // Load Bitmap Font
	SetCurrentDir(Path + "\\font");
    BitmapFont1->Glyphs->LoadFromFile("darkgold_font.bmp");

    // Load and setup sound samples
    // Load and setup sound samples
    SetCurrentDir(Path + "\\audio");
    GLSoundLibrary->Samples->Add()->LoadFromFile("ChillyWind.mp3");
    GLSoundLibrary->Samples->Add()->LoadFromFile("howl.mp3");
    // Could've been done at design time, but then it hurts the eyes ;)
    GLSceneViewer1->Buffer->BackgroundColor = clWhite;
    // Move camera starting point to an interesting hand-picked location
    DummyCube1->Position->X = 570;
    DummyCube1->Position->Z = -385;
    DummyCube1->Turn(90);
    // Initial camera height offset (controled with pageUp/pageDown)
    FCamHeight = 10;

    randomize();
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLCadencer1Progress(
    TObject* Sender, const double deltaTime, const double newTime)
{
    float speed;

    // handle keypresses
    if (IsKeyDown(VK_SHIFT))
        speed = 5 * deltaTime;
    else
        speed = deltaTime;
    TGLCoordinates* c = GLCamera1->Position;
    if (IsKeyDown(VK_UP))
        DummyCube1->Translate(c->Z * speed, 0, -c->X * speed);
    if (IsKeyDown(VK_DOWN))
        DummyCube1->Translate(-c->Z * speed, 0, c->X * speed);
    if (IsKeyDown(VK_LEFT))
        DummyCube1->Translate(-c->X * speed, 0, -c->Z * speed);
    if (IsKeyDown(VK_RIGHT))
        DummyCube1->Translate(c->X * speed, 0, c->Z * speed);
    if (IsKeyDown(VK_PRIOR))
        FCamHeight = FCamHeight + 10 * speed;
    if (IsKeyDown(VK_NEXT))
        FCamHeight = FCamHeight - 10 * speed;
    if (IsKeyDown(VK_ESCAPE))
        Close();

    // don't drop through terrain!
    DummyCube1->Position->Y =
        TerrainRenderer1->InterpolatedHeight(DummyCube1->Position->AsVector) +
        FCamHeight;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLSceneViewer1MouseDown(
    TObject* Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
    my = Y;
    mx = X;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLSceneViewer1MouseMove(
    TObject* Sender, TShiftState Shift, int X, int Y)
{
    if (Shift.Contains(ssLeft)) {
        GLCamera1->MoveAroundTarget((my - Y) * 0.5, (mx - X) * 0.5);
        mx = X;
        my = Y;
    }
}

//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject* Sender)
{
    String s;
    //  s.printf("%.1f FPS - %d", GLSceneViewer1->FramesPerSecond(),
    //		   TerrainRenderer1->LastTriangleCount());
    HUDText1->Text = s;
    GLSceneViewer1->ResetPerformanceMonitor();
}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormKeyPress(TObject* Sender, char &Key)
{
    TGLMaterial* fp;
    TGLFogEnvironment* fe;
    TGIFColor Color;

    switch (Key) {
        case 'w':
        case 'W':
            fp = GLMaterialLibrary1->Materials->Items[0]->Material;
            if (fp->PolygonMode == pmLines)
                fp->PolygonMode = pmFill;
            else
                fp->PolygonMode = pmLines;
            break;
        case '+':
            if (GLCamera1->DepthOfView < 2000) {
                GLCamera1->DepthOfView = GLCamera1->DepthOfView * 1.2;
                fe = GLSceneViewer1->Buffer->FogEnvironment;
                fe->FogEnd = fe->FogEnd * 1.2;
                fe->FogStart = fe->FogStart * 1.2;
            }
            break;
        case '-':
            if (GLCamera1->DepthOfView > 300) {
                GLCamera1->DepthOfView = GLCamera1->DepthOfView / 1.2;
                fe = GLSceneViewer1->Buffer->FogEnvironment;
                fe->FogEnd = fe->FogEnd / 1.2;
                fe->FogStart = fe->FogStart / 1.2;
            }
            break;
        case '*':
            if (TerrainRenderer1->CLODPrecision > 20)
                TerrainRenderer1->CLODPrecision =
                    RoundInt(TerrainRenderer1->CLODPrecision * 0.8);
            break;
        case '/':
            if (TerrainRenderer1->CLODPrecision < 1000)
                TerrainRenderer1->CLODPrecision =
                    RoundInt(TerrainRenderer1->CLODPrecision * 1.2);
            break;
        case '8':
            if (TerrainRenderer1->QualityDistance > 40)
                TerrainRenderer1->QualityDistance =
                    RoundInt(TerrainRenderer1->QualityDistance * 0.8);
            break;
        case '9':
            if (TerrainRenderer1->QualityDistance < 1000)
                TerrainRenderer1->QualityDistance =
                    RoundInt(TerrainRenderer1->QualityDistance * 1.2);
            break;
        case 'n':
        case 'N':
            if (SkyDome1->Stars->Count == 0) {
                // turn on 'night' mode
                Color.Red = 0;
                Color.Green = 0;
                Color.Blue = 8;
                SkyDome1->Bands->Items[0]->StopColor->AsWinColor =
                    TGIFColorMap::RGB2Color(Color);
                Color.Red = 0;
                Color.Green = 0;
                Color.Blue = 0;
                SkyDome1->Bands->Items[0]->StartColor->AsWinColor =
                    TGIFColorMap::RGB2Color(Color);
                Color.Red = 0;
                Color.Green = 0;
                Color.Blue = 16;
                SkyDome1->Bands->Items[1]->StopColor->AsWinColor =
                    TGIFColorMap::RGB2Color(Color);
                Color.Red = 0;
                Color.Green = 0;
                Color.Blue = 8;
                SkyDome1->Bands->Items[1]->StartColor->AsWinColor =
                    TGIFColorMap::RGB2Color(Color);

                SkyDome1->Stars->AddRandomStars(
                    700, clWhite, True); // many white stars
                Color.Red = 255;
                Color.Green = 100;
                Color.Blue = 100;
                SkyDome1->Stars->AddRandomStars(100,
                    TGIFColorMap::RGB2Color(Color), True); // some redish ones
                Color.Red = 100;
                Color.Green = 100;
                Color.Blue = 255;
                SkyDome1->Stars->AddRandomStars(100,
                    TGIFColorMap::RGB2Color(Color), True); // some blueish ones
                Color.Red = 255;
                Color.Green = 255;
                Color.Blue = 100;
                SkyDome1->Stars->AddRandomStars(100,
                    TGIFColorMap::RGB2Color(Color),
                    True); // some yellowish ones

                GLSceneViewer1->Buffer->BackgroundColor = clBlack;
                fe = GLSceneViewer1->Buffer->FogEnvironment;
                fe->FogColor->AsWinColor = clBlack;
                fe->FogStart =
                    -fe->FogStart; // Fog is used to make things darker

                SPMoon->Visible = True;
                SPSun->Visible = False;
                GLLensFlare->Visible = False;
            }
            break;
        case 'd':
        case 'D':
            if (SkyDome1->Stars->Count > 0) {
                // turn on 'day' mode
                SkyDome1->Bands->Items[1]->StopColor->Color = clrNavy;
                SkyDome1->Bands->Items[1]->StartColor->Color = clrBlue;
                SkyDome1->Bands->Items[0]->StopColor->Color = clrBlue;
                SkyDome1->Bands->Items[0]->StartColor->Color = clrWhite;
                SkyDome1->Stars->Clear();
                GLSceneViewer1->Buffer->BackgroundColor = clWhite;
                fe = GLSceneViewer1->Buffer->FogEnvironment;
                fe->FogColor->AsWinColor = clWhite;
                fe->FogStart = -fe->FogStart;

                GLSceneViewer1->Buffer->FogEnvironment->FogStart = 0;
                SPMoon->Visible = False;
                SPSun->Visible = True;
            }
            break;
        case 't':
            if (SkyDome1->Options.Contains(sdoTwinkle))
                SkyDome1->Options = SkyDome1->Options << sdoTwinkle;
            else
                SkyDome1->Options = SkyDome1->Options >> sdoTwinkle;
            break;
        case 'l':
            GLLensFlare->Visible = (!GLLensFlare->Visible) && SPSun->Visible;
    }
    Key = '\0';
}

//---------------------------------------------------------------------------

void __fastcall TForm1::TISoundTimer(TObject* Sender)
{
    TGLVector wolfPos;
    float c, s;
    TGLBSoundEmitter* be;

    if (!GLSMBASS1->Active)
        return;
    if (SkyDome1->Stars->Count == 0) {
        // wind blows around camera
        be = GetOrCreateSoundEmitter(GLCamera1);
        be->Source->SoundLibrary = GLSoundLibrary;
        be->Source->SoundName = GLSoundLibrary->Samples->Items[0]->Name;
        be->Source->Volume = random() * 0.5 + 0.5;
        be->Playing = True;
    } else {
        // wolf howl at some distance, at ground level
        wolfPos = GLCamera1->AbsolutePosition;
        SinCosine(
            random() * Gls::Vectorgeometry::c2PI, 100 + random(1000), s, c);
        wolfPos.X = wolfPos.X + c;
        wolfPos.Z = wolfPos.Z + s;
        wolfPos.Y = TerrainRenderer1->InterpolatedHeight(wolfPos);
        DCSound->Position->AsVector = wolfPos;
        be = GetOrCreateSoundEmitter(DCSound);
        be->Source->SoundLibrary = GLSoundLibrary;
        be->Source->SoundName = GLSoundLibrary->Samples->Items[1]->Name;
        be->Source->MinDistance = 100;
        be->Source->MaxDistance = 4000;
        be->Playing = True;
    }
    TISound->Enabled = False;
    TISound->Interval = 10000 + random(10000);
    TISound->Enabled = True;
}

//---------------------------------------------------------------------------

